home *** CD-ROM | disk | FTP | other *** search
/ The Learning Curve / The Learning Curve (Weird Science, 1996).iso / geography / drawmap / pop.c < prev    next >
C/C++ Source or Header  |  1989-09-24  |  24KB  |  717 lines

  1. /*
  2.  *  The functions for pop-up menus
  3.  *
  4.  *  Written by Derek Zahn (Gambit Software, Madison WI), July 1987
  5.  *
  6.  *  This code is freely distributable and is blessed by its author for
  7.  *  inclusion, in this form or any other, into Amiga programs,
  8.  *  commercial or non-commercial.  If this is done, no credit must be
  9.  *  given to me (although I wouldn't mind).
  10.  *
  11.  *  This code was developed and tested under Manx Aztec C, version 3.40a
  12.  *  with small code, small data, and short integers as part of the Gambit
  13.  *  Software development environment.  It has been "unGambitized" for
  14.  *  general use.  I am unfamiliar with other Amiga C compilers, so cannot
  15.  *  speculate on any porting difficulties.  This file was created with a
  16.  *  text editor (Z) whose tabstops were set to 8, so that it may be easily
  17.  *  and intelligibly printed.  This code was developed under 1.2; I am
  18.  *  not sure if it will work under 1.1, but can't see why not.
  19.  *
  20.  *  Note that there are some features that should be supported but are not,
  21.  *  and some issues about the function and interface that make me nervous.
  22.  *  These are explained in the appendix to the documentation.  I would
  23.  *  greatly appreciate receiving any enhancements and modifications to this
  24.  *  code, or suggestions therefor.  Comments on techniques and coding
  25.  *  style are always appreciated.  Enjoy.
  26.  */
  27.  
  28. /* include files */
  29.  
  30. #include <exec/types.h>
  31. #include <intuition/intuitionbase.h>
  32. #include <intuition/intuition.h>
  33. #include <graphics/gfxmacros.h>
  34. #include "popmenu.h"
  35.  
  36. /* Externally defined functions used in this module */
  37.  
  38. extern struct Window *OpenWindow();
  39. extern struct IntuiMessage *GetMsg();  /* type coercion, true... */
  40.  
  41. extern VOID CloseWindow(), ReplyMsg(), Wait();
  42. extern VOID RectFill(), Move(), Draw(), Text(), PrintIText(), DrawImage();
  43.  
  44. /* The following functions are defined in this module */
  45.  
  46. extern LONG PopChoose();               /* blocking user interface */
  47.                                        /*   -- exported           */
  48. extern SHORT pop_computestate();       /* see who is selected, */
  49.                                        /*   if anybody         */
  50. extern VOID pop_highlight();           /* highlight the specified item */
  51. extern VOID pop_unhighlight();         /* unhighlight the specified item */
  52. extern VOID pop_do_highlighting();     /* high or un high light the item */
  53. extern VOID pop_render();              /* draws the title (if existent) */
  54.                                        /*   and menu items              */
  55. extern VOID pop_draw_menuitem();       /* draws the menu item */
  56. extern struct MenuItem *pop_getitem(); /* find a MenuItem struc */
  57. extern SHORT pop_strlen();             /* local strlen() */
  58.  
  59. /* This is structure will be used to create a window for display of the    */
  60. /* menu.  In my heart of hearts, I wanted to use graphics library          */
  61. /* functions instead, but reason prevailed.  Note the use of the RMBTRAP   */
  62. /* flag -- while the pop-up menu is being processed, there is no use for   */
  63. /* the right button.  Perhaps this should only be set if the right button  */
  64. /* has some bearing on the pop-up menu.                                    */
  65.  
  66. static struct NewWindow pop_window =  {
  67.    0, 0,                               /* LeftEdge, TopEdge: will be */
  68.                                        /*   filled in later          */
  69.    0, 0,                               /* Width, Height: will be */
  70.                                        /*   filled in later      */
  71.    (UBYTE) -1, (UBYTE) -1,             /* BlockPen, DetailPen */
  72.    MOUSEBUTTONS | MOUSEMOVE,           /* IDCMP flags */
  73.    SMART_REFRESH | REPORTMOUSE | ACTIVATE | RMBTRAP, /* flags */
  74.    NULL,                               /* no gadgets */
  75.    NULL,                               /* checkmark inherited later */
  76.    NULL,                               /* no title */
  77.    NULL,                               /* Screen -- will be filled in later */
  78.    NULL,                               /* No custom bitmap */
  79.    0, 0,                               /* MinWidth, MinHeight -- no change */
  80.                                        /*   in size necessary              */
  81.    0, 0,                               /* MaxWidth, MaxHeight -- no change */
  82.                                        /*   in size necessary              */
  83.    CUSTOMSCREEN                        /* always use this value */
  84. };
  85.  
  86. /* It is assumed that the following point to bases of opened libraries     */
  87.  
  88. extern struct IntuitionBase *IntuitionBase;
  89. extern struct GfxBase *GfxBase;
  90.  
  91. /* ============================================================= */
  92.  
  93. /*
  94.  * PopChoose (menu, win)
  95.  * menu -- pointer to the menu to pop
  96.  * win -- the window to which this menu relates.  NULL means the currently
  97.  * active window.
  98.  *
  99.  * This function provides a blocking pop-up menu.  It returns (LONG) -1 if 
  100.  * either an error occurred attempting to pop or if no selection was made
  101.  * by the user.  If a selection was made, a LONG between 0 and n-1, where
  102.  * n is the number of Menu Items.
  103.  *
  104.  * -1 is also returned if a selection of a checked item was made.
  105.  *
  106.  * Since this code opens a window, it is up to the caller to be sure that
  107.  * no scribbling in droll ways is done while this code is in progress.
  108.  */
  109.  
  110. LONG PopChoose (menu, win)
  111.  
  112. struct Menu *menu;
  113. struct Window *win;
  114.  
  115. {
  116.    struct Screen *screen;              /* the window's screen */
  117.    struct Window *popwin;              /* the pop-up menu */
  118.    struct IntuiMessage *message;       /* our eyes and ears */
  119.    struct MenuItem *sel_item;          /* the selected item */
  120.    SHORT pop_state, pop_newstate;      /* menu selection state varaibles */
  121.    SHORT mouse_moved;                  /* keeps track of whether the */
  122.                                        /*   mouse has moved          */
  123.    SHORT finished;                     /* set when menu should be blown away */
  124.    SHORT class;                        /* incoming IntuiMessage class */
  125.    SHORT code;                         /* incoming IntuiMessage code */
  126.    ULONG exclude;                      /* for handling mutual exclusion */
  127.  
  128.    /* Check to see that IntuitionBase and GfxBase are non-null.       */
  129.    /* While this is not any sort of guarantee against disaster, it    */
  130.    /* is better than nothing.                                         */
  131.  
  132.    if ((IntuitionBase == NULL) || (GfxBase == NULL))
  133.       return ((LONG) (-1));
  134.  
  135.    /* One paranoid check */
  136.  
  137.    if (menu == NULL)
  138.       return ((LONG) (-1));
  139.  
  140.    /* If the menu is not MENUENABLED, nothing to do                   */
  141.  
  142.    if (!(menu->Flags & MENUENABLED))
  143.       return ((LONG) (-1));
  144.  
  145.    /* Form the menu window to blast forth into the Visual World. Note */
  146.    /* the unconventional (and inconsistent with Intuition) ways that  */
  147.    /* the Width and Height fields are used here.                      */
  148.  
  149.    pop_window.Width = menu->Width;
  150.    pop_window.Height = menu->Height;
  151.  
  152.    if (win == NULL)
  153.       win = IntuitionBase->ActiveWindow;
  154.    if (win == NULL)                     /* panic */
  155.       return ((LONG) (-1));
  156.  
  157.    /* Inherit CheckMark from the "parent" window                      */
  158.  
  159.    if (win->CheckMark)
  160.       pop_window.CheckMark = win->CheckMark;
  161.  
  162.    screen = win->WScreen;
  163.    pop_window.Screen = screen;
  164.  
  165.    pop_window.LeftEdge = menu->LeftEdge;
  166.    pop_window.TopEdge = menu->TopEdge;
  167.  
  168.    /* if we are supposed to return to the last-selected menu item and */
  169.    /* such a beast exists, all other positioning information (except  */
  170.    /* POPTIDY) will be circumvented.  The menu will appear under the  */
  171.    /* pointer with the last-chosen item pre-selected, if this is      */
  172.    /* possible given the POPTIDY flag and the screen constraints.     */
  173.    /* In this case, the LeftEdge and TopEdge fields of the menu       */
  174.    /* structure will have been altered (I know, ick!) to provide a    */
  175.    /* relative offset with respect to the pointer to do the deed      */
  176.  
  177.    if ((menu->Flags & POPREMEMBER) && (menu->Flags & POPUSED))  {
  178.       pop_window.LeftEdge += screen->MouseX;
  179.       pop_window.TopEdge += screen->MouseY;
  180.    }
  181.    else  {
  182.       if (menu->Flags & POPPOINTREL)  {
  183.          pop_window.LeftEdge += screen->MouseX;
  184.          pop_window.TopEdge += screen->MouseY;
  185.       }
  186.       else if (menu->Flags & POPWINREL)  {
  187.          pop_window.LeftEdge += win->LeftEdge;
  188.          pop_window.TopEdge += win->TopEdge;
  189.       }
  190.    }
  191.  
  192.    /* If the caller wishes us to be POPTIDY, the menu must completely */
  193.    /* appear on the screen, whatever other effects this may have on   */
  194.    /* menu positioning.  The left edge and top edge must be altered   */
  195.    /* accordingly.  In the pathological case where the menu is larger */
  196.    /* than the screen, -1 is returned.                                */
  197.    /* If poptidiness is not a factor, the size of the window may have */
  198.    /* to be altered if it shoots off the bottom or right edge of the  */
  199.    /* screen.  There should be some similar mechanism to deal with    */
  200.    /* the menu if it extends past the top or left edge of the screen; */
  201.    /* as it stands now, the OpenWindow() call will fail, and the      */
  202.    /* result may be even more dire under 1.1.  Use 1.2!               */
  203.  
  204.    if (menu->Flags & POPTIDY)  {
  205.       if ((pop_window.Width > screen->Width) || 
  206.          (pop_window.Height > screen->Height))
  207.             return ((LONG) (-1));
  208.       if (pop_window.LeftEdge + pop_window.Width > screen->Width)
  209.          pop_window.LeftEdge = screen->Width-pop_window.Width;
  210.       if (pop_window.TopEdge + pop_window.Height > screen->Height)
  211.          pop_window.TopEdge=screen->Height-pop_window.Height;
  212.       if (pop_window.LeftEdge < screen->LeftEdge)
  213.          pop_window.LeftEdge = screen->LeftEdge;
  214.       if (pop_window.TopEdge < screen->TopEdge)
  215.          pop_window.TopEdge = screen->TopEdge;
  216.    }
  217.    else  {
  218.       if (pop_window.LeftEdge + pop_window.Width > screen->Width)
  219.          pop_window.Width = screen->Width - pop_window.LeftEdge;
  220.       if (pop_window.TopEdge + pop_window.Height > screen->Height)
  221.          pop_window.Height = screen->Height - pop_window.TopEdge;
  222.    }
  223.  
  224.    /* There!  Finally, the window is ready to be displayed!  First,   */
  225.    /* create it.                                                      */
  226.  
  227.    popwin = OpenWindow (&pop_window);
  228.    if (popwin == NULL)                 /* all that work for nuthin' */
  229.       return ((LONG) (-1));
  230.  
  231.    /* Now, render the menu items and (possibly) the menu title.       */
  232.  
  233.    pop_render (popwin, menu);
  234.  
  235.    /* Now, see if the pointer is over a selection.  The variable      */
  236.    /* 'pop_state' will from this point on hold the value, in linear   */
  237.    /* traversal order of the MenuItems (zero-indexed), the currently  */
  238.    /* selected menu item, or -1 if none are selected.                 */
  239.  
  240.    pop_state = pop_computestate (popwin, menu);
  241.  
  242.    /* If one is indeed currently selected, highlight it.              */
  243.  
  244.    if (pop_state >= 0)
  245.       pop_highlight (popwin, menu, pop_state);
  246.  
  247.    /* Here is the IDCMP loop that will process the pop-up menu.  Note */
  248.    /* that on mousemove events, I don't care where it moved, just if  */
  249.    /* it did -- pop_computestate() will figure out where by reaching  */
  250.    /* into the Window structure.  Not Pure Programming, somehow, but  */
  251.    /* blessed by the Intuition manual.                                */
  252.  
  253.    finished = 0;
  254.    while (1)  {
  255.       mouse_moved = 0;
  256.       Wait ((ULONG) 1L << popwin->UserPort->mp_SigBit);
  257.       while (message = GetMsg (popwin->UserPort))  {
  258.          class = message->Class;
  259.          code = message->Code;
  260.          ReplyMsg (message);
  261.  
  262.          /* The only messages we should be getting are      */
  263.          /* mouse button and move events.  Button events    */
  264.          /* could signify the end of this routine's         */
  265.          /* epheremal spotlight role.                       */
  266.  
  267.          switch (class)  {
  268.          case MOUSEMOVE:
  269.             mouse_moved = 1;
  270.             break;
  271.          case MOUSEBUTTONS:
  272.             switch (code)  {
  273.             case SELECTDOWN:
  274.                if ((menu->Flags & POPLEFTBUTTON) &&
  275.                 (menu->Flags & POPTRIGGERDOWN))
  276.                    finished = 1;
  277.                break;
  278.             case SELECTUP:
  279.                if ((menu->Flags & POPLEFTBUTTON) &&
  280.                 (menu->Flags & POPTRIGGERUP))
  281.                    finished = 1;
  282.                break;
  283.             case MENUDOWN:
  284.                if ((menu->Flags & POPRIGHTBUTTON) &&
  285.                 (menu->Flags & POPTRIGGERDOWN))
  286.                    finished = 1;
  287.                break;
  288.             case MENUUP:
  289.                if ((menu->Flags & POPRIGHTBUTTON) &&
  290.                 (menu->Flags & POPTRIGGERUP))
  291.                    finished = 1;
  292.                break;
  293.             default:                   /* huh? */
  294.                break;
  295.             }
  296.             break;
  297.          default:                      /* huh? */
  298.             break;
  299.          }
  300.       }
  301.  
  302.       /* if the exit conditions have been met, we can return our */
  303.       /* results with honor and dignity, having served.          */
  304.       /* Note that if we are remembering the last selection, the */
  305.       /* menu structure is mangled to make that possible.        */
  306.  
  307.       if (finished)  {
  308.          pop_state = pop_computestate (popwin, menu);
  309.          if (pop_state >= 0)  {
  310.             if (menu->Flags & POPREMEMBER)  {
  311.                menu->Flags |= POPUSED;
  312.                menu->LeftEdge = -1 * popwin->MouseX;
  313.                menu->TopEdge =  -1 * popwin->MouseY;
  314.             }
  315.  
  316.             /* Special things to do if the menu entry  */
  317.             /* is of type CHECKIT                      */
  318.  
  319.             sel_item = pop_getitem (menu, pop_state);
  320.             if (sel_item->Flags & CHECKIT)  {
  321.                if (sel_item->Flags & CHECKED)  {
  322.                   pop_state = -1;
  323.                   if (sel_item->Flags & MENUTOGGLE)
  324.                      sel_item->Flags &= ~CHECKED;
  325.                }
  326.                else  {
  327.                   sel_item->Flags |= CHECKED;
  328.  
  329.                   /* Handle mutual exclusion */
  330.  
  331.                   exclude = sel_item->MutualExclude;
  332.                   if (exclude)  {
  333.                      sel_item = menu->FirstItem;
  334.                      while (sel_item)  {
  335.                         if (exclude & 1)
  336.                            sel_item->Flags &= ~CHECKED;
  337.                         exclude >>= 1;
  338.                         sel_item = sel_item->NextItem;
  339.                      }
  340.                   }
  341.                }
  342.             }
  343.          }
  344.          CloseWindow (popwin);
  345.          return ((LONG) pop_state);
  346.       }
  347.  
  348.       /* if the mouse has moved, find out its new state and      */
  349.       /* alter the highlighting accordingly.                     */
  350.  
  351.       if (mouse_moved)  {
  352.          pop_newstate = pop_computestate (popwin, menu);
  353.          if (pop_newstate != pop_state)  {
  354.             if (pop_state >= 0)
  355.                pop_unhighlight (popwin, menu, pop_state);
  356.             if (pop_newstate >= 0)
  357.                pop_highlight (popwin, menu, pop_newstate);
  358.             pop_state = pop_newstate;
  359.          }
  360.       }
  361.    }
  362. }
  363.  
  364. /* ============================================================= */
  365.  
  366. /*
  367.  * pop_computestate()
  368.  *
  369.  * This function checks to see where the mouse pointer is in relation to
  370.  * the various menu items in the menu.  If it is inside one of them, it
  371.  * returns which one (indexed by its linear position in the MenuItem list
  372.  * with 0 being the first one).  If not, returns -1.
  373.  *
  374.  * Possible future enhancement: keep a set of state variables containing
  375.  * the UL and LR corners of the last-known select box; this would make
  376.  * a quick check possible and would cut down the computation for short
  377.  * mouse movements (the most common).
  378.  */
  379.  
  380. static SHORT pop_computestate (win, menu)
  381. struct Window *win;
  382. struct Menu *menu;
  383.  
  384. {
  385.  
  386.    register SHORT current = 0;
  387.    register SHORT xval, yval;
  388.    register struct MenuItem *item;
  389.  
  390.    /* Get the x and y vals of the mouse position */
  391.  
  392.    xval = win->MouseX;
  393.    yval = win->MouseY;
  394.  
  395.    /* If there is a title, decrement the yval by the correct amount */
  396.  
  397.    if (menu->MenuName)
  398.       yval -= POPTITLEHEIGHT;
  399.  
  400.    /* First, see if the pointer is even in the window */
  401.  
  402.    if ((xval < 0) || (yval < 0) ||
  403.       (xval > win->Width) || (yval > win->Height))
  404.          return (-1);
  405.  
  406.    /* search through the list of menu items, checking the select box  */
  407.    /* of each.  If containment is detected, the job is done.          */
  408.  
  409.    item = menu->FirstItem;
  410.    while (item)  {
  411.       if ((xval >= item->LeftEdge) && (yval >= item->TopEdge) &&
  412.          (xval <= item->LeftEdge + item->Width) &&
  413.          (yval <= item->TopEdge + item->Height))  {
  414.  
  415.          /* We have found the quarry; now, the result only  */
  416.          /* depends on the MenuItem's ITEMENABLED flag.     */
  417.  
  418.          if (item->Flags & ITEMENABLED)
  419.             return (current);
  420.          else
  421.             return (-1);
  422.       }
  423.       current++;
  424.       item = item->NextItem;
  425.    }
  426.  
  427.    /* If the list is exhausted, return the sad news */
  428.  
  429.    return (-1);
  430. }
  431.  
  432. /* ============================================================= */
  433.  
  434. /*
  435.  * pop_highlight()
  436.  *
  437.  * highlight a menu item
  438.  */
  439.  
  440. static VOID pop_highlight (win, menu, state)
  441.  
  442. struct Window *win;
  443. struct Menu *menu;
  444. SHORT state;
  445.  
  446. {
  447.  
  448.    pop_do_highlighting (win, menu, state, 0);
  449.  
  450. }
  451.  
  452. /* ============================================================= */
  453.  
  454. /*
  455.  * pop_unhighlight()
  456.  *
  457.  * unhighlight a menu item
  458.  */
  459.  
  460. static VOID pop_unhighlight (win, menu, state)
  461.  
  462. struct Window *win;
  463. struct Menu *menu;
  464. SHORT state;
  465.  
  466. {
  467.  
  468.    pop_do_highlighting (win, menu, state, 1);
  469.  
  470. }
  471.  
  472. /* ============================================================= */
  473.  
  474. /*
  475.  * pop_do_highlighting()
  476.  *
  477.  * Highlight or unhighlight a menu item, given its traversal number.  Assumes
  478.  * this is a rational value -- if it isn't, Watch Out.
  479.  */
  480.  
  481. static VOID pop_do_highlighting (win, menu, state, mode)
  482.  
  483. struct Window *win;
  484. struct Menu *menu;
  485. SHORT state;
  486. SHORT mode;                            /* 0 means to highlight,  */
  487.                                        /* 1 means to unhighlight */
  488.  
  489. {
  490.  
  491.    register struct MenuItem *item;
  492.    struct RastPort *rp;
  493.    SHORT offset = 0;
  494.  
  495.    if (menu->MenuName)
  496.       offset = POPTITLEHEIGHT;
  497.  
  498.    /* Get the correct MenuItem structure */
  499.  
  500.    item = pop_getitem (menu, state);
  501.  
  502.    rp = win->RPort;
  503.  
  504.    /* Now, do the highlighting!  The action to be taken depends on    */
  505.    /* the type of highlighting desired for this item.                 */
  506.    /* The way that the flags for highlighting works is truly bizarre  */
  507.  
  508.    if ((item->Flags & HIGHNONE) == HIGHNONE)
  509.       return;
  510.  
  511.    if (item->Flags & HIGHCOMP)  {
  512.       SetDrMd (rp, COMPLEMENT);
  513.       RectFill (rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge +
  514.         offset), (LONG) (item->LeftEdge + item->Width - 1),
  515.         (LONG) (item->TopEdge + item->Height + offset));
  516.    }
  517.    else if (item->Flags & HIGHBOX)  {
  518.       SetDrMd (rp, COMPLEMENT);
  519.       Move (rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge + 
  520.         offset));
  521.       Draw (rp, (LONG) (item->LeftEdge + item->Width - 1),
  522.         (LONG) (item->TopEdge + offset));
  523.       Draw (rp, (LONG) (item->LeftEdge + item->Width - 1),
  524.         (LONG) (item->TopEdge + item->Height + offset));
  525.       Draw (rp, (LONG) item->LeftEdge,
  526.         (LONG) (item->TopEdge + item->Height + offset));
  527.       Draw (rp, (LONG) item->LeftEdge, (LONG) 
  528.         (item->TopEdge + offset));
  529.    }
  530.  
  531.    /*  Otherwise, the mode is HIGHIMAGE */
  532.  
  533.    else
  534.       pop_draw_menuitem (win, item, !mode, offset);
  535. }
  536.  
  537. /* ============================================================= */
  538.  
  539. /*
  540.  * pop_render()
  541.  *
  542.  * renders the menu title (if existent) and the menu items
  543.  */
  544.  
  545. static VOID pop_render (win, menu)
  546.  
  547. struct Window *win;
  548. struct Menu *menu;
  549.  
  550. {
  551.  
  552.    struct MenuItem *item;
  553.    struct RastPort *rp;
  554.    SHORT offset = 0;
  555.  
  556.    rp = win->RPort;
  557.  
  558.    /* Fill the background with color 1, like Intuition Menus */
  559.  
  560.    SetAPen (rp, 1L);
  561.    RectFill (rp, 0L, 0L, (LONG) win->Width, (LONG) win->Height);
  562.  
  563.    /* First, if there is a Title for this menu, render it in the top */
  564.    /* of the menu.                                                   */
  565.  
  566.    if (menu->MenuName)  {
  567.       SetDrMd (rp, JAM1);
  568.       SetAPen (rp, 0L);
  569.       SetBPen (rp, 1L);
  570.       Move (rp, 4L, 7L);
  571.       Text (rp, menu->MenuName, (LONG) pop_strlen(menu->MenuName));
  572.       SetDrMd (rp, COMPLEMENT);
  573.       RectFill (rp,0L,0L, (LONG) win->Width, (LONG) POPTITLEHEIGHT);
  574.       SetDrMd (rp, JAM1);
  575.       offset = POPTITLEHEIGHT;
  576.    }
  577.  
  578.    /* now render all of the menu items */
  579.  
  580.    item = menu->FirstItem;
  581.    while (item)  {
  582.       pop_draw_menuitem (win, item, 0, offset);
  583.       item = item->NextItem;
  584.    }
  585. }
  586.  
  587. /* ============================================================= */
  588.  
  589. /* Area fill patterns */
  590.  
  591. static USHORT pop_ghost_pattern[] = {
  592.    0x1111, 0x4444
  593. };
  594. static USHORT pop_normal_pattern[] = {
  595.    0xffff, 0xffff
  596. };
  597.  
  598. /* ============================================================= */
  599.  
  600. /*
  601.  * pop_draw_menuitem()
  602.  *
  603.  * Draws the specified menuitem in the given rastport.  The mode argument
  604.  * says what to draw -- 0 means draw the ItemFill, 1 the SelectFill.
  605.  */
  606.  
  607. static VOID pop_draw_menuitem (win, item, mode, offset)
  608.  
  609. struct Window *win;
  610. struct MenuItem *item;
  611. SHORT mode;
  612. SHORT offset;
  613.  
  614. {
  615.  
  616.    APTR fill;
  617.    struct RastPort *rp;
  618.  
  619.    /* first, figure out what to do, and return if it is a NULL thing */
  620.  
  621.    if (!mode)
  622.       fill = item->ItemFill;
  623.    else
  624.       fill = item->SelectFill;
  625.  
  626.    if (!fill)
  627.       return;
  628.  
  629.    rp = win->RPort;
  630.  
  631.    /* First, erase what may already be there, just to be sure that    */
  632.    /* everything works out all right.                                 */
  633.  
  634.    SetAPen (rp, 1L);
  635.    SetDrMd (rp, JAM1);
  636.    RectFill (rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge +
  637.      offset), (LONG) (item->LeftEdge + item->Width), (LONG)
  638.      (item->TopEdge + item->Height + offset));
  639.  
  640.    /* If the item is checkmarked, draw the checkmark.  Intuition made */
  641.    /* sure that the CheckMark field of the window structure exists    */
  642.  
  643.    if (item->Flags & CHECKIT)
  644.       if (item->Flags & CHECKED)
  645.          DrawImage (rp, win->CheckMark, (LONG)  item->LeftEdge,
  646.            (LONG) (item->TopEdge + offset + 1));
  647.  
  648.    /* Now, draw the item itself -- depending on the Flag value, it    */
  649.    /* could be either an Image or an IntuiText                        */
  650.  
  651.    if (item->Flags & ITEMTEXT)
  652.       PrintIText (rp, fill, (LONG) item->LeftEdge, 
  653.         (LONG) (item->TopEdge + offset));
  654.    else
  655.       DrawImage (rp, fill, (LONG) item->LeftEdge, 
  656.         (LONG) (item->TopEdge + offset));
  657.  
  658.    /* If the ITEMENABLED flag is not set, "ghost" the item.           */
  659.  
  660.    if (!(item->Flags & ITEMENABLED))  {
  661.       SetAPen (rp, 1L);
  662.       SetDrMd (rp, JAM1);
  663.       SetAfPt (rp, (USHORT *) pop_ghost_pattern, 1L);
  664.       RectFill (rp, (LONG) item->LeftEdge, (LONG) (item->TopEdge +
  665.         offset), (LONG) (item->LeftEdge + item->Width), (LONG)
  666.         (item->TopEdge + item->Height + offset));
  667.       SetAfPt (rp, (USHORT *) pop_normal_pattern, 1L);
  668.    }
  669. }
  670.  
  671. /* ============================================================= */
  672.  
  673. /*
  674.  * pop_getitem()
  675.  *
  676.  * given the traversal number of a menu item in a menu (assumes, BTW, that
  677.  * the arguments are valid), return a pointer to the MenuItem structure
  678.  */
  679.  
  680. static struct MenuItem *pop_getitem (menu, which)
  681.  
  682. struct Menu *menu;
  683. SHORT which;
  684.  
  685. {
  686.  
  687.    struct MenuItem *item;
  688.  
  689.    item = menu->FirstItem;
  690.    while (which--)
  691.       item = item->NextItem;
  692.    return (item);
  693. }
  694.  
  695. /* ============================================================= */
  696.  
  697. /*
  698.  * pop_strlen()
  699.  *
  700.  * a home-brewed strlen to prevent it being necessary to hook in whatever
  701.  * huge object file in which the c library's strlen() resides.
  702.  */
  703.  
  704. static SHORT pop_strlen (str)
  705.  
  706. char *str;
  707.  
  708. {
  709.  
  710.    register SHORT count = 0;
  711.  
  712.    for (; *str++; count++);
  713.    return (count);
  714. }
  715.  
  716. /* :-) */
  717.